﻿Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.Activities
    <ActivityValidator(GetType(EventHandlingScopeValidator)), SRDescription("EventHandlingScopeActivityDescription"), Designer(GetType(EventHandlingScopeDesigner), GetType(IDesigner)), ToolboxItem(GetType(ActivityToolboxItem)), ToolboxBitmap(GetType(EventHandlingScopeActivity), "Resources.Sequence.png")> _
    Public NotInheritable Class EventHandlingScopeActivity
        Inherits CompositeActivity
        Implements IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs)
        ' Methods
        Public Sub New()
        End Sub

        Public Sub New(ByVal name As String)
            MyBase.New(name)
        End Sub

        Protected Overrides Function Cancel(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Dim bodyActivity As Activity = Me.BodyActivity
            Dim eventHandlersActivity As EventHandlersActivity = Me.EventHandlersActivity
            If ((bodyActivity Is Nothing) AndAlso (eventHandlersActivity Is Nothing)) Then
                Return ActivityExecutionStatus.Closed
            End If
            Dim flag As Boolean = False
            If ((Not bodyActivity Is Nothing) AndAlso (bodyActivity.ExecutionStatus = ActivityExecutionStatus.Executing)) Then
                executionContext.CancelActivity(bodyActivity)
                flag = True
            End If
            If ((Not eventHandlersActivity Is Nothing) AndAlso (eventHandlersActivity.ExecutionStatus = ActivityExecutionStatus.Executing)) Then
                executionContext.CancelActivity(eventHandlersActivity)
                flag = True
            End If
            If ((Not flag AndAlso ((bodyActivity Is Nothing) OrElse ((bodyActivity.ExecutionStatus <> ActivityExecutionStatus.Faulting) AndAlso (bodyActivity.ExecutionStatus <> ActivityExecutionStatus.Canceling)))) AndAlso ((eventHandlersActivity Is Nothing) OrElse ((eventHandlersActivity.ExecutionStatus <> ActivityExecutionStatus.Faulting) AndAlso (eventHandlersActivity.ExecutionStatus <> ActivityExecutionStatus.Canceling)))) Then
                Return ActivityExecutionStatus.Closed
            End If
            Return MyBase.ExecutionStatus
        End Function

        Protected Overrides Function Execute(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Dim bodyActivity As Activity = Me.BodyActivity
            If (bodyActivity Is Nothing) Then
                Return ActivityExecutionStatus.Closed
            End If
            Dim eventHandlersActivity As EventHandlersActivity = Me.EventHandlersActivity
            If (Not eventHandlersActivity Is Nothing) Then
                eventHandlersActivity.RegisterForStatusChange(Activity.ClosedEvent, Me)
                executionContext.ExecuteActivity(eventHandlersActivity)
            End If
            bodyActivity.RegisterForStatusChange(Activity.ClosedEvent, Me)
            executionContext.ExecuteActivity(bodyActivity)
            Return MyBase.ExecutionStatus
        End Function

        Protected Overrides Sub OnActivityChangeRemove(ByVal executionContext As ActivityExecutionContext, ByVal removedActivity As Activity)
            MyBase.OnActivityChangeRemove(executionContext, removedActivity)
            If TypeOf removedActivity Is EventHandlersActivity Then
                Me.eventHandlersRemovedInDynamicUpdate = True
            Else
                Me.bodyActivityRemovedInDynamicUpdate = True
            End If
        End Sub

        Protected Overrides Sub OnWorkflowChangesCompleted(ByVal executionContext As ActivityExecutionContext)
            MyBase.OnWorkflowChangesCompleted(executionContext)
            If (MyBase.ExecutionStatus = ActivityExecutionStatus.Executing) Then
                If Me.bodyActivityRemovedInDynamicUpdate Then
                    If ((Me.EventHandlersActivity Is Nothing) OrElse (Me.EventHandlersActivity.ExecutionStatus = ActivityExecutionStatus.Closed)) Then
                        executionContext.CloseActivity
                    ElseIf (Me.EventHandlersActivity.ExecutionStatus = ActivityExecutionStatus.Executing) Then
                        Me.EventHandlersActivity.UnsubscribeAndClose
                    End If
                End If
                If (Me.eventHandlersRemovedInDynamicUpdate AndAlso ((Me.BodyActivity Is Nothing) OrElse (Me.BodyActivity.ExecutionStatus = ActivityExecutionStatus.Closed))) Then
                    executionContext.CloseActivity
                End If
            End If
            Me.eventHandlersRemovedInDynamicUpdate = False
            Me.bodyActivityRemovedInDynamicUpdate = False
        End Sub

        Private Sub System.Workflow.ComponentModel.IActivityEventListener<System.Workflow.ComponentModel.ActivityExecutionStatusChangedEventArgs>.OnEvent(ByVal sender As Object, ByVal e As ActivityExecutionStatusChangedEventArgs) Implements IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs).OnEvent
            Dim context As ActivityExecutionContext = [TryCast](sender,ActivityExecutionContext)
            If (context Is Nothing) Then
                Throw New ArgumentException
            End If
            e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, Me)
            If TypeOf e.Activity Is EventHandlersActivity Then
                If (Me.BodyActivity.ExecutionStatus = ActivityExecutionStatus.Closed) Then
                    context.CloseActivity
                End If
            Else
                Dim eventHandlersActivity As EventHandlersActivity = Me.EventHandlersActivity
                If ((eventHandlersActivity Is Nothing) OrElse (eventHandlersActivity.ExecutionStatus = ActivityExecutionStatus.Closed)) Then
                    context.CloseActivity
                Else
                    eventHandlersActivity.UnsubscribeAndClose
                End If
            End If
        End Sub


        ' Properties
        Friend ReadOnly Property BodyActivity As Activity
            Get
                Dim activity As Activity = Nothing
                Dim activity2 As Activity
                For Each activity2 In MyBase.EnabledActivities
                    If Not TypeOf activity2 Is EventHandlersActivity Then
                        activity = activity2
                    End If
                Next
                Return activity
            End Get
        End Property

        Friend ReadOnly Property EventHandlersActivity As EventHandlersActivity
            Get
                Dim activity As EventHandlersActivity = Nothing
                Dim activity2 As Activity
                For Each activity2 In MyBase.EnabledActivities
                    If TypeOf activity2 Is EventHandlersActivity Then
                        activity = [TryCast](activity2,EventHandlersActivity)
                    End If
                Next
                Return activity
            End Get
        End Property


        ' Fields
        <NonSerialized> _
        Private bodyActivityRemovedInDynamicUpdate As Boolean
        <NonSerialized> _
        Private eventHandlersRemovedInDynamicUpdate As Boolean
    End Class
End Namespace

